3158de645a0e0e9e0aeab1e1b8cf57bfbad14ca2,src/com/limelight/nvstream/http/PairingManager.java,PairingManager,pair,#String#String#,169

Before Change


				"/pair?uniqueid="+uniqueId+"&devicename=roth&updateState=1&serverchallengeresp="+bytesToHex(challengeRespEncrypted),
				true);
		if (!NvHTTP.getXmlString(secretResp, "paired").equals("1")) {
			http.openHttpConnectionToString(http.baseUrlHttps + "/unpair?uniqueid="+uniqueId, true);
			return PairState.FAILED;
		}
		

After Change


		// Send the salt and get the server cert. This doesn't have a read timeout
		// because the user must enter the PIN before the server responds
		String getCert = http.openHttpConnectionToString(http.baseUrlHttp +
				"/pair?"+http.buildUniqueIdUuidString()+"&devicename=roth&updateState=1&phrase=getservercert&salt="+
				bytesToHex(salt)+"&clientcert="+bytesToHex(pemCertBytes),
				false);
		if (!NvHTTP.getXmlString(getCert, "paired").equals("1")) {
			http.openHttpConnectionToString(http.baseUrlHttp + "/unpair?"+http.buildUniqueIdUuidString(), true);
			return PairState.FAILED;
		}
		X509Certificate serverCert = extractPlainCert(getCert);
		
		// Generate a random challenge and encrypt it with our AES key
		byte[] randomChallenge = generateRandomBytes(16);
		byte[] encryptedChallenge = encryptAes(randomChallenge, aesKey);
		
		// Send the encrypted challenge to the server
		String challengeResp = http.openHttpConnectionToString(http.baseUrlHttp + 
				"/pair?"+http.buildUniqueIdUuidString()+"&devicename=roth&updateState=1&clientchallenge="+bytesToHex(encryptedChallenge),
				true);
		if (!NvHTTP.getXmlString(challengeResp, "paired").equals("1")) {
			http.openHttpConnectionToString(http.baseUrlHttp + "/unpair?"+http.buildUniqueIdUuidString(), true);
			return PairState.FAILED;
		}
		
		// Decode the server's response and subsequent challenge
		byte[] encServerChallengeResponse = hexToBytes(NvHTTP.getXmlString(challengeResp, "challengeresponse"));
		byte[] decServerChallengeResponse = decryptAes(encServerChallengeResponse, aesKey);
		
		byte[] serverResponse = Arrays.copyOfRange(decServerChallengeResponse, 0, 20);
		byte[] serverChallenge = Arrays.copyOfRange(decServerChallengeResponse, 20, 36);
		
		// Using another 16 bytes secret, compute a challenge response hash using the secret, our cert sig, and the challenge
		byte[] clientSecret = generateRandomBytes(16);
		byte[] challengeRespHash = toSHA1Bytes(concatBytes(concatBytes(serverChallenge, cert.getSignature()), clientSecret));
		byte[] challengeRespEncrypted = encryptAes(challengeRespHash, aesKey);
		String secretResp = http.openHttpConnectionToString(http.baseUrlHttp +
				"/pair?"+http.buildUniqueIdUuidString()+"&devicename=roth&updateState=1&serverchallengeresp="+bytesToHex(challengeRespEncrypted),
				true);
		if (!NvHTTP.getXmlString(secretResp, "paired").equals("1")) {
			http.openHttpConnectionToString(http.baseUrlHttp + "/unpair?"+http.buildUniqueIdUuidString(), true);
			return PairState.FAILED;
		}
		
		// Get the server's signed secret
		byte[] serverSecretResp = hexToBytes(NvHTTP.getXmlString(secretResp, "pairingsecret"));
		byte[] serverSecret = Arrays.copyOfRange(serverSecretResp, 0, 16);
		byte[] serverSignature = Arrays.copyOfRange(serverSecretResp, 16, 272);

		// Ensure the authenticity of the data
		if (!verifySignature(serverSecret, serverSignature, serverCert)) {
			// Cancel the pairing process
			http.openHttpConnectionToString(http.baseUrlHttp + "/unpair?"+http.buildUniqueIdUuidString(), true);
			
			// Looks like a MITM
			return PairState.FAILED;